//  JSManager.h
//
//  SweetpomeII
//  THIS IS NOT A OPEN SOURCE PROJECT!
//
//  Created by cc on 12-5-16.
//  Copyright (c) 2009-2012 Chukong Technologies, Inc. 触控科技 版权所有
//  All rights reserved.
//

#ifndef _JSBIND_JSMANAGER_H_CC_
#define _JSBIND_JSMANAGER_H_CC_

#include "ModuleDefine.h"

/**
 *	@brief	jsbind namespace. use spidermonkey js engine.
 */
namespace SP_JSBind
{
    static int tt_ccc = 0 ;
    
	extern JSClass globalClass ;
	extern void Default_Error_Reporter(JSContext* cx, const char* msg, JSErrorReport* report) ;
    extern JSFunctionSpec g_Functions[];
    
	/**
	 *	@brief	jsbind manager class.
	 */
	class CJSManager
	{
	public:
		/**
		 *	@brief	singleton mode.
		 *
		 *	@return	return jsmanager pointer.
		 */
		static CJSManager* Instance()
		{
            __ENTER_FUNCTION
			if (NULL == s_pManager)
			{
				s_pManager = new CJSManager() ;
			}
            __EXIT_FUNCTION("CJSManager::Instance\n")
			return s_pManager ;
		}
		/**
		 *	@brief	execute script from string.
		 *
		 *	@param 	jsstr 	script string.
		 *
		 *	@return	true.
		 */
		bool ExecuteScriptFromString(const char* jsstr)
		{
            __ENTER_FUNCTION
			jsval rval;
			uintN lineno = 0;
			JS_EvaluateScript(m_pContext, m_pGlobalObj, jsstr, ::strlen(jsstr), NULL, lineno, &rval) ;
            
            __EXIT_FUNCTION("CJSManager::ExecuteScriptFromString\n")
			return true ;
		}
		/**
		 *	@brief	execute script from jsfile.
		 *
		 *	@param 	jsfile 	js filename.
		 *
		 *	@return	true.
		 */
		bool ExecuteScriptFromFile(const char* jsfile)
		{
            __ENTER_FUNCTION
            
            for (JSScriptMap::iterator itr = m_apScripts.begin(); itr != m_apScripts.end(); ++itr)
            {
                if (0 == strcmp(itr->first, jsfile))
                {
                    jsval value ;
                    JS_ExecuteScript(m_pContext, m_pGlobalObj, itr->second, &value) ;
                    return true ;
                }
            }
            
            //            const JSScriptMap::iterator js = m_apScripts.find(jsfile);
            //            if (js != m_apScripts.end()) {
            //                jsval value ;
            //                JS_ExecuteScript(m_pContext, m_pGlobalObj, js->second, &value) ;
            //                return true ;
            //            }
            
            
            JSScript* script ;
			script = JS_CompileFile(m_pContext, m_pGlobalObj, jsfile) ;
            
			jsval value ;
			JS_ExecuteScript(m_pContext, m_pGlobalObj, script, &value) ;
            //			JS_DestroyScript(m_pContext, script) ;
            
            printf(" ==== compile jsfile [%s] [%d]\n", jsfile, ++tt_ccc) ;
            char* p = new char[strlen(jsfile)+1] ;
            memset(p, 0, strlen(jsfile)+1) ;
            strcpy(p, jsfile) ;
            m_apScripts.insert(JSScriptMap::value_type(p, script)) ;
            
            __EXIT_FUNCTION("CJSManager::ExecuteScriptFromFile\n")
			return true ;
		}
        
	public:
		/**
		 *	@brief	get js runtime.
		 *
		 *	@return	js runtime.
		 */
		JSRuntime* GetRuntime() { return m_pRuntime ; } ;
		/**
		 *	@brief	get js context.
		 *
		 *	@return	js context.
		 */
		JSContext* GetContext() { return m_pContext ; } ;
		/**
		 *	@brief	get js global object.
		 *
		 *	@return	js global object.
		 */
		JSObject*  GetObject()  { return m_pGlobalObj ; } ;
        
	private:
        /**
         *	@brief	constructor method.
         */
		CJSManager()
		{
            __ENTER_FUNCTION
			long rsize = (8L * 1024L * 1024L * 10) ;
			int ssize = (8 * 1024) ;
            
            srand((unsigned int)time(NULL)) ;
            
			m_pRuntime = JS_NewRuntime(rsize) ;
            
			m_pContext = JS_NewContext(m_pRuntime, ssize) ;
            
			m_pGlobalObj = JS_NewObject(m_pContext, &globalClass, NULL, NULL) ;
            
			JS_InitStandardClasses(m_pContext, m_pGlobalObj) ;
            JS_DefineFunctions( m_pContext, m_pGlobalObj, g_Functions);
			SetOptions(JSOPTION_VAROBJFIX | JSOPTION_COMPILE_N_GO) ;
			JS_SetErrorReporter(m_pContext, Default_Error_Reporter) ;
            __EXIT_FUNCTION("CJSManager::CJSManager\n")
		}
        /**
         *	@brief	destructor method.
         */
		~CJSManager()
		{
            __ENTER_FUNCTION
			JS_DestroyContext(m_pContext);
			JS_DestroyRuntime(m_pRuntime);
			JS_ShutDown() ;
            __EXIT_FUNCTION("CJSManager::~CJSManager\n")
		}
	private:
		/**
		 *	@brief	js set options function.
		 *
		 *	@param 	flag 	set JSOPTION_VAROBJFIX value.
		 */
		void SetOptions(unsigned int flag)
		{
            __ENTER_FUNCTION
			JS_SetOptions(m_pContext, JS_GetOptions(m_pContext) | flag) ;
            __EXIT_FUNCTION("CJSManager::SetOptions\n")
		}
		/**
		 *	@brief	if run js has error, will call this function.
		 *
		 *	@param 	func 	function pointer.
		 */
		void SetErrorReportFunc(void (*func)(JSContext* cx, const char* msg, JSErrorReport* report))
		{
            __ENTER_FUNCTION
			JS_SetErrorReporter(m_pContext, func) ;
            __EXIT_FUNCTION("CJSManager::SetErrorReportFunc\n")
		}
        
	private:
        //        std::list<char*>    m_lsJSFiles ;
        typedef std::map<const char*, JSScript*> JSScriptMap;
        JSScriptMap m_apScripts ;
		/**
		 *	@brief	js runtime.
		 */
		JSRuntime*    m_pRuntime ;
		/**
		 *	@brief	js runtime.
		 */
		JSContext*    m_pContext ;
		/**
		 *	@brief	js runtime.
		 */
		JSObject*     m_pGlobalObj ;
	private:
		static CJSManager* s_pManager ;
	} ;
}

#endif


















